﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace ToWaTimeReportMVC4.Models
{
    public class ToWaService
    {

        ToWaTimeReportMVC4Entities db = new ToWaTimeReportMVC4Entities();

        public User ValidateUser(string username, string password)
        {
            User user = null;
            try
            {
                user = db.Users.Single(u => u.Username == username);
            }
            catch { }
            if (user != null)
            {
                if (user.Password.CompareTo(password) == 0)
                {
                    return user;
                }
            }
            return null;
        }

        public User GetUserById(int id)
        {
            User user = db.Users.Single(u => u.Id == id);

            return user;
        }

        public User GetUserByUsername(string username)
        {
            User user = null;
            try
            {
                user = db.Users.Single(u => u.Username == username);
            }
            catch { }

            return user;
        }

        public Job GetJobById(int id)
        {
            Job job = db.Jobs.Single(j => j.Id == id);

            return job;
        }

        public string GetJobDescriptionByJobId(int id)
        {
            var description = db.Jobs.Single(j => j.Id == id).Description;

            return description.ToString();
        }

        public Project GetProjectById(int id)
        {
            Project project = db.Projects.Single(p => p.Id == id);

            return project;
        }

        public List<Project> GetProjectsByConsultant(User consultant, DateTime from, DateTime to)
        {
            bool CheckDates = false;
            if (from != null && to != null)
            {
                if (from.Millisecond < to.Millisecond)
                {
                    CheckDates = true;
                }
            }
            List<UserToJob> JobIds = db.UserToJobs.Where(r => r.UserId == consultant.Id).ToList();
            List<int> Jobs = new List<int>();
            foreach (UserToJob j in JobIds)
            {
                if (CheckDates)
                {
                    if (j.Job.StartTime.CompareTo(from) >= 0 && j.Job.EndTime.CompareTo(to) <= 0)
                    {
                        Jobs.Add(j.Job.ProjectId);
                    }
                }
                else
                {
                    Jobs.Add(j.Job.ProjectId);
                }
            }
            Jobs = Jobs.Distinct().ToList();
            List<Project> Projects = new List<Project>();
            foreach (int i in Jobs)
            {
                Projects.Add(GetProjectById(i));
            }
            return Projects;
        }

        public void AddJobFromJobView(JobView jobView, int consultantId)
        {
            string startTime = jobView.StartTime;
            string endTime = jobView.EndTime;
            DateTime start;
            DateTime end;
            if (!string.IsNullOrEmpty(startTime))
            {
                startTime = startTime.Replace('/', '-');
            }
            if (!string.IsNullOrEmpty(endTime))
            {
                endTime = endTime.Replace('/', '-');
            }
            try
            {
                start = DateTime.Parse(startTime);
            }
            catch
            {
                start = DateTime.Now;
            }
            try
            {
                end = DateTime.Parse(endTime);
            }
            catch
            {
                end = DateTime.Now.AddHours(1);
            }

            AddJob(start, end, jobView.Description, int.Parse(jobView.SelectedValue), consultantId); 
            //Job job = new Job();
            //job.StartTime = start;
            //job.EndTime = end;
            //job.Description = jobView.Description;
            //job.ProjectId = Convert.ToInt32(jobView.SelectedValue);
            //db.Jobs.Add(job);
            //db.SaveChanges();
            //User u = service.GetUserByUsername(User.Identity.Name);
            //db.UserToJobs.Add(new UserToJob { JobId = job.Id, UserId = u.Id });
            //db.SaveChanges();
        }

        public void AddJob(DateTime startTime, DateTime endTime, string description, int projectId, int consultantId)
        {
            Job newJob = new Job();
            newJob.StartTime = startTime;
            newJob.EndTime = endTime;
            newJob.Description = description;
            newJob.ProjectId = projectId;
            db.Jobs.Add(newJob);
            db.SaveChanges();

            db.UserToJobs.Add(new UserToJob { JobId = newJob.Id, UserId = consultantId });
            db.SaveChanges();
        }

        public void AddProject(string name, int costumerId, string description)
        {
            Project project = new Project();
            project.Name = name;
            project.UserId = costumerId;
            project.Description = description;
            db.Projects.Add(project);
            db.SaveChanges();
        }

        public void AddUser(string username, string password, string salt, string email, int type, int salary, int hoursWorked)
        {
            //User user = new User();
            //user.Username = username;
            //user.Password = password;
            //if (salt != null && salt.Length > 0)
            //{
            //    user.Salt = salt;
            //}
            //else
            //{
            //    user.Salt = "";
            //}
            //user.Email = email;
            //user.Type = type;
            //user.Salary = salary;
            //user.HoursWorked = hoursWorked;
            db.Users.Add(new User { Username = username, Password = password, Salt = salt, Salary = salary, Email = email, Type = type, HoursWorked = hoursWorked });
            db.SaveChanges();
        }

        public void AddConsultantToJob(User consultant, Job job)
        {
            if (consultant.Type == 2)
            {
                db.UserToJobs.Add(new UserToJob { JobId = job.Id, UserId = consultant.Id });
                db.SaveChanges();
            }
        }

        public string GetTypeOfUserByUsername(string username)
        {
            User user = null;
            try
            {
                user = db.Users.Single(u => u.Username == username);
            }
            catch { }

            if (user != null)
            {
                if (user.Type == 0)
                {
                    return "Admin";
                }
                else if (user.Type == 1)
                {
                    return "Customer";
                }
                else if (user.Type == 2)
                {
                    return "Consultant";
                }
                else
                {
                    return "Not a valid type.";
                }
            }
            else
            {
                return "No user found.";
            }
        }

        public int ConvertTypeToInt(string stringType)
        {
            if (stringType.CompareTo("Admin") == 0)
            {
                return 0;
            }
            else if (stringType.CompareTo("Customer") == 0)
            {
                return 1;
            }
            else if (stringType.CompareTo("Consultant") == 0)
            {
                return 2;
            }
            return -1;
        }

        public string ConvertTypeToString(int stringType)
        {
            if (stringType == 0)
            {
                return "Admin";
            }
            else if (stringType == 1)
            {
                return "Customer";
            }
            else if (stringType == 2)
            {
                return "Consultant";
            }
            return "";
        }

        public List<UserProjectWrapper> GetAdminIndexList()
        {
            List<User> allUsers = db.Users.ToList();
            List<Project> allProjects = db.Projects.ToList();

            List<UserProjectWrapper> wrapper = new List<UserProjectWrapper>();

            foreach (User u in allUsers)
            {
                UserProjectWrapper upWrapper = new UserProjectWrapper();
                upWrapper.user = u;
                wrapper.Add(upWrapper);
            }
            foreach (Project p in allProjects)
            {
                UserProjectWrapper upWrapper = new UserProjectWrapper();
                upWrapper.project = p;
                wrapper.Add(upWrapper);
            }
            return wrapper;
        }

        public bool RemoveUserById(int id)
        {
            User user = db.Users.Single(u => u.Id == id);
            try
            {
                db.Users.Remove(user);
                db.SaveChanges();
                return true;
            }
            catch
            {
                return false;
            }
        }

        public List<User> GetAllCustomers()
        {
            List<User> allCustomers = db.Users.Where(t => t.Type == 1).ToList();
            return allCustomers;
        }

        public List<User> GetAllConsultant()
        {
            List<User> allCustomers = db.Users.Where(t => t.Type == 2).ToList();
            return allCustomers;
        }

        public List<ProjectWrapper> GetProjectsByCustomerId(int id)
        {
            List<Project> projects = db.Projects.Where(c => c.UserId == id).ToList();
            List<ProjectWrapper> projWrapper = new List<ProjectWrapper>();
            foreach (Project p in projects)
            {
                ProjectWrapper pWrapper = new ProjectWrapper();
                pWrapper.Id = p.Id;
                pWrapper.Name = p.Name;
                pWrapper.Description = p.Description;
                pWrapper.UserId = p.UserId;
                projWrapper.Add(pWrapper);
            }

            return projWrapper;
        }

        public int GetProjectCost(int id)
        {
            Project project = GetProjectById(id);
            List<Job> jobs = db.Jobs.Where(j => j.ProjectId == project.Id).ToList();
            int cost = 0;
            foreach (Job job in jobs)
            {
                List<UserToJob> uTjs = db.UserToJobs.Where(u => u.JobId == job.Id).ToList();
                foreach (UserToJob uTj in uTjs)
                {
                    User consultant = GetUserById(uTj.UserId);
                    cost += (int)consultant.Salary * HoursWorkedBetweenDates(job.EndTime - job.StartTime);
                }
            }
            return cost;
        }

        public int GetProjectCostBetweenDates(int id, DateTime start, DateTime end)
        {
            Project project = GetProjectById(id);
            List<Job> jobs = db.Jobs.Where(j => j.ProjectId == project.Id && j.StartTime >= start && j.EndTime <= end).ToList();
            int cost = 0;
            foreach (Job job in jobs)
            {
                List<UserToJob> uTjs = db.UserToJobs.Where(u => u.JobId == job.Id).ToList();
                foreach (UserToJob uTj in uTjs)
                {
                    User consultant = GetUserById(uTj.UserId);
                    cost += (int)consultant.Salary * HoursWorkedBetweenDates(job.EndTime - job.StartTime);
                }
            }
            return cost;
        }

        private int HoursWorkedBetweenDates(TimeSpan timeSpan)
        {
            int days = timeSpan.Days;
            int hours = timeSpan.Hours;
            //hours += (timeSpan.Minutes + 30) % 60;
            int hoursWorked = days * 24 + hours;

            return hoursWorked;
        }

        public float GetBelaggningsGradForConsultant(User consultant, int belaggningsgrad)
        {
            List<Job> jobs = GetJobsByConsultantId(consultant.Id);
            int hoursWorked = 0;
            foreach (Job job in jobs)
            {
                hoursWorked += HoursWorkedBetweenDates(job.EndTime - job.StartTime);
            }
            return hoursWorked / belaggningsgrad;
        }

        public List<Job> GetJobsByConsultantId(int id)
        {
            List<UserToJob> uTjs = db.UserToJobs.Where(u => u.UserId == id).ToList();
            List<Job> jobs = new List<Job>();
            foreach (UserToJob uTj in uTjs)
            {
                jobs = db.Jobs.Where(j => j.Id == uTj.JobId).ToList();
            }
            return jobs;
        }

        public List<SelectListItem>  GetProjectsDropDown()
        {
            List<Project> pList = db.Projects.ToList();
            List<SelectListItem> select = new List<SelectListItem>();
            foreach (Project p in pList)
            {
                select.Add(new SelectListItem
                {
                    Text = p.Name,
                    Value = "" + p.Id
                });
            }
            return select;
        }

        public List<SelectListItem> GetConsultantDropDown()
        {
            List<User> consultants = GetAllConsultant();
            List<SelectListItem> select = new List<SelectListItem>();
            select.Add(new SelectListItem { Text = "All Consultants", Value = "-1" });
            foreach (User u in consultants)
            {
                select.Add(new SelectListItem
                {
                    Text = u.Username,
                    Value = "" + u.Id
                });
            }
            return select;
        }

        public List<JobView> GetJobViewList(string username)
        {
            User u = GetUserByUsername(username);
            return GetJobViewList(u.Id);
        }

        public List<JobView> GetJobViewList(int consultId)
        {
            List<UserToJob> linking = db.UserToJobs.Where(m => m.UserId == consultId).ToList();
            List<JobView> jobViewList = new List<JobView>();
            foreach (UserToJob j in linking)
            {
                jobViewList.Add(getJobViewFromJob(GetJobById(j.JobId)));
            }
            return jobViewList;
        }

        public bool RemoveProjectById(int id)
        {
            Project project = db.Projects.Single(p => p.Id == id);
            try
            {
                db.Projects.Remove(project);
                db.SaveChanges();
                return true;
            }
            catch
            {
                return false;
            }
        }

        public Rapport GetRapportForConsultant(string username, string startTime, string endTime, int normal)
        {
            User u = GetUserByUsername(username);
            return GetRapportForConsultant(u.Id, startTime, endTime, normal);
        }
        public Rapport GetRapportForConsultant(int ConsultantId, string startTime, string endTime, int normal)
        {
            DateTime start;
            DateTime end;
            if (!string.IsNullOrEmpty(startTime))
            {
                startTime = startTime.Replace('/', '-');
            }
            if (!string.IsNullOrEmpty(endTime))
            {
                endTime = endTime.Replace('/', '-');
            }
            try
            {
                start = DateTime.Parse(startTime);
            }
            catch
            {
                start = DateTime.Now.AddDays(-7);
            }
            try
            {
                end = DateTime.Parse(endTime);
            }
            catch
            {
                end = DateTime.Now;
            }
            User u = GetUserById(ConsultantId);
            List<UserToJob> linking = db.UserToJobs.Where(m => m.UserId == u.Id).ToList();
            List<Job> jobs = new List<Job>();
            foreach (UserToJob utj in linking)
            {
                jobs.Add(GetJobById(utj.JobId));
            }
            Dictionary<int, int> dictionary = new Dictionary<int, int>();
            foreach (Job j in jobs)
            {
                int h = 0;
                if (dictionary.TryGetValue(j.ProjectId, out h))
                    dictionary.Remove(j.ProjectId);
                h += HoursWorkedBetweenDates(j.EndTime - j.StartTime);
                dictionary.Add(j.ProjectId, h);
            }
            List<ProjectJob> projectJobs = new List<ProjectJob>();
            int total = 0;
            foreach (KeyValuePair<int, int> pair in dictionary)
            {
                ProjectJob proJob = new ProjectJob();
                proJob.projectId = pair.Key;
                proJob.projectName = GetProjectById(pair.Key).Name;
                proJob.hours = pair.Value;
                projectJobs.Add(proJob);
                total += proJob.hours;
            }
            int overtime = total - normal;
            if (overtime < 0)
                overtime = 0;
            return new Rapport { ConsultantId = u.Id, ConsultantName = u.Username,ProjectJobs = projectJobs, total = total, overtime = overtime };
        }

        private JobView getJobViewFromJob(Job job)
        {
            JobView v = new JobView();
            v.Description = job.Description;
            v.StartTime = job.StartTime.ToString("yyyy-MM-dd HH:mm");
            v.EndTime = job.EndTime.ToString("yyyy-MM-dd HH:mm");
            v.ProjectName = GetProjectById(job.ProjectId).Name;
            v.hours = 0;
            return v;
        }

        public List<ConsultantWrapper> GetConsultantsWorkedHoursByProjectId(int id, DateTime start, DateTime end)
        {
            List<Job> jobs = db.Jobs.Where(j => j.ProjectId == id && j.StartTime >= start && j.EndTime <= end).ToList();
            List<ConsultantWrapper> consultants = new List<ConsultantWrapper>();
            foreach (Job job in jobs)
            {
                List<UserToJob> uTjs = db.UserToJobs.Where(u => u.JobId == job.Id).ToList();
                foreach (UserToJob uTj in uTjs)
                {
                    ConsultantWrapper consultantWrapper = new ConsultantWrapper();
                    consultantWrapper.ProjectId = id;
                    consultantWrapper.Consultant = GetUserById(uTj.UserId);
                    consultantWrapper.TimeSpent = GetTimeSpentOnJobByConsultantAndProjectId(consultantWrapper.Consultant, id, start, end);

                    if (!consultants.Contains(consultantWrapper))
                    {
                        consultants.Add(consultantWrapper);
                    }
                }
            }
            
            return consultants;
        }

        private int GetTimeSpentOnJobByConsultantAndProjectId(User user, int projectId, DateTime start, DateTime end)
        {
            List<UserToJob> connection = db.UserToJobs.Where(u => u.UserId == user.Id).ToList();
            List<Job> jobs = new List<Job>();
            int timeSpent = 0;
            foreach (UserToJob uTj in connection)
            {
                jobs = db.Jobs.Where(v => v.Id == uTj.JobId && v.StartTime >= start && v.EndTime <= end && v.ProjectId == projectId).ToList();
                foreach (Job job in jobs)
                {
                    timeSpent += HoursWorkedBetweenDates(job.EndTime - job.StartTime);
                }
            }
            return timeSpent;
        }
    }
}